package com.easylinkin.linkappapi.classroom.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.classroom.entity.ClassroomDevice;
import com.easylinkin.linkappapi.classroom.mapper.GfdRoleRefAreaMapper;
import com.easylinkin.linkappapi.classroom.service.ClassroomService;
import com.easylinkin.linkappapi.common.constant.CommonConstant;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.deviceattributestatus.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import com.easylinkin.linkappapi.deviceservice.entity.DeviceServices;
import com.easylinkin.linkappapi.deviceservice.service.DeviceServiceService;
import com.easylinkin.linkappapi.openapi.dto.ApiDownResultDTO;
import com.easylinkin.linkappapi.security.constant.LinkappUserConstant;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappRole;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.service.LinkappUserService;
import com.easylinkin.linkappapi.space.entity.LinkappArea;
import com.easylinkin.linkappapi.space.mapper.LinkappAreaMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * class info :
 *
 * @author liuqihang
 * @date 2021/9/2 15:25
 */
@Service
@Slf4j
public class ClassroomServiceImpl implements ClassroomService {

    @Resource
    private DeviceServiceService deviceServiceService;

    @Resource
    private DeviceMapper deviceMapper;

    @Resource
    private DeviceAttributeStatusService deviceAttributeStatusService;

    @Resource
    GfdRoleRefAreaMapper gfdRoleRefAreaMapper;

    @Resource
    LinkappAreaMapper linkappAreaMapper;

    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    LinkappUserService linkappUserService;

    @Value("${linkapp.airControllerDelay}")
    public Long delayTime;

    private static String deviceUnitCode_d = "KGJSQ-433-01-0054";
    private static String deviceUnitCode_c = "DTUA-4G-02-03-0013";
    private static String deviceUnitCode_z = "ZK-GFKD-01-0999";

    @Override
    public IPage<ClassroomDevice> getAreaDevicePage(Page page, LinkappArea linkappArea) {
        //获取拥有子级的空间区域，即所有parentId
        List<String> containParentIdArea = linkappAreaMapper.getContainParentIdArea(linkappArea.getAreaPath());
        IPage<ClassroomDevice> mostChildAreaPage = linkappAreaMapper.getMostChildArea(page, linkappArea.getAreaPath(), containParentIdArea);
        if(mostChildAreaPage == null){
            return null;
        }
        List<ClassroomDevice> mostChildAreaList = mostChildAreaPage.getRecords();
        if(ObjectUtils.isEmpty(mostChildAreaList)){
            return null;
        }
        List<String> areaIds = mostChildAreaList.stream().map(ClassroomDevice::getId).collect(Collectors.toList());

        //灯控
        Device device = new Device();
        device.setAreaIds(areaIds);
        List<String> deviceUnitCodeList = new ArrayList<String>();
        deviceUnitCodeList.add(deviceUnitCode_d);
        //窗帘
        deviceUnitCodeList.add(deviceUnitCode_c);
        //中控设备
        deviceUnitCodeList.add(deviceUnitCode_z);
        device.setDeviceUnitCodeList(deviceUnitCodeList);

        List<Device> devices = deviceMapper.getMonitorDevices(device);
        for (Device device1 : devices) {
            List<DeviceAttributeStatus> deviceAttributeList = device1.getDeviceAttributeStatusList();
            deviceAttributeList = deviceAttributeStatusService.getFormatDeviceAttributeStatusList(deviceAttributeList);
            device1.setDeviceAttributeStatusList(deviceAttributeList);
        }
        if(ObjectUtils.isNotEmpty(devices)){
            Map<String, List<Device>> collect = devices.stream().collect(Collectors.groupingBy(Device::getAreaId));
            for (ClassroomDevice crd:
                    mostChildAreaList) {
                crd.setDeviceList(collect.get(crd.getId()));
            }
        }
        return mostChildAreaPage;
    }

    @Override
    public ApiDownResultDTO send(DeviceServices deviceServices) {
        Map<String, Object> downParameter = deviceServices.getDownParameter();
        String deviceUnitCode = (String) downParameter.get("device_unit_code");
        String switchState = (String) downParameter.get("switch_state");
        Assert.notNull(deviceUnitCode, "deviceUnitCode 不能为空");
        Assert.notNull(switchState, "switchState 不能为空");
        List<String> deviceIdList = (List<String>)downParameter.get("device_id");

        List<Map<String, Object>> paramList = fillParams(deviceUnitCode, switchState);

        ApiDownResultDTO send = null;
        for (String deviceCode:
                deviceIdList) {
            for (Map<String, Object> downParameterMap:
                    paramList) {
                downParameterMap.put("device_id",deviceCode);
                log.info("classroom send:{}", downParameterMap);
                send = deviceServiceService.send(downParameterMap);
            }
        }
        return send;
    }

    private List<Map<String, Object>> fillParams(String deviceUnitCode, String switchStateStr){
        List<Map<String, Object>> paramList = new ArrayList<>();
        Integer switchState = Integer.valueOf(switchStateStr);
        if(deviceUnitCode_d.equals(deviceUnitCode)){
            Map<String, Object> downParamsMap = new HashMap<String, Object>(CommonConstant.MAP_DEFAULT_INITIAL_CAPACITY);
            Map<String, Object> downParamsMapChild = new HashMap<String, Object>(CommonConstant.MAP_DEFAULT_INITIAL_CAPACITY);
            downParamsMapChild.put("switch_state", switchState);
            downParamsMap.put("parameter", downParamsMapChild);
            downParamsMap.put("service_id", "switch_control");
            paramList.add(downParamsMap);
        }
        else if(deviceUnitCode_c.equals(deviceUnitCode)){
            Map<String, Object> downParamsMap01 = new HashMap<String, Object>(CommonConstant.MAP_DEFAULT_INITIAL_CAPACITY);
            downParamsMap01.put("service_id", "child_device_downlink");
            Map<String, Object> downParamsMapChild01 = new HashMap<String, Object>(CommonConstant.MAP_DEFAULT_INITIAL_CAPACITY);
            downParamsMapChild01.put("switch_control", switchState);
            downParamsMapChild01.put("device_id", "01");
            downParamsMap01.put("parameter", downParamsMapChild01);
            paramList.add(downParamsMap01);

            Map<String, Object> downParamsMap02 = new HashMap<String, Object>(CommonConstant.MAP_DEFAULT_INITIAL_CAPACITY);
            downParamsMap02.put("service_id", "child_device_downlink");
            Map<String, Object> downParamsMapChild02 = new HashMap<String, Object>(CommonConstant.MAP_DEFAULT_INITIAL_CAPACITY);
            downParamsMapChild02.put("switch_control", switchState);
            downParamsMapChild02.put("device_id", "02");
            downParamsMap02.put("parameter", downParamsMapChild02);
            paramList.add(downParamsMap02);
        }
        else if(deviceUnitCode_z.equals(deviceUnitCode)){
            Map<String, Object> downParamsMap = new HashMap<String, Object>(CommonConstant.MAP_DEFAULT_INITIAL_CAPACITY);
            Map<String, Object> downParamsMapChild = new HashMap<String, Object>(CommonConstant.MAP_DEFAULT_INITIAL_CAPACITY);
            downParamsMapChild.put("control_order", switchState);
            downParamsMap.put("parameter", downParamsMapChild);
            downParamsMap.put("service_id", "podium_switch");
            paramList.add(downParamsMap);
        }
        return paramList;
    }

    @Override
    public ApiDownResultDTO batchSend(DeviceServices deviceServices) {
        ApiDownResultDTO result = null;
        Map<String, Object> downParameter = deviceServices.getDownParameter();
        List<String> deviceIdList = (List<String>)downParameter.get("device_id");
        if(ObjectUtils.isEmpty(deviceIdList)){
            result = new ApiDownResultDTO();
            result.setCode("1");
            result.setMsg("device_id不能为空");
            return result;
        }
        if(deviceIdList.size() == 1){
            result = send(deviceServices);
        }else {
            Thread thead = new Thread(new Runnable() {
                @Override
                public void run() {
                   asyncBatchSend(deviceServices);
                }
            });
            thead.start();
            result = new ApiDownResultDTO();
            result.setCode("0");
            result.setMsg("批量下发完成");
            return result;
        }
        return result;
    }

    @Override
    public void asyncBatchSend(DeviceServices deviceServices){
        Map<String, Object> downParameter = deviceServices.getDownParameter();
        String deviceUnitCode = (String) downParameter.get("device_unit_code");
        String switchState = (String) downParameter.get("switch_state");
        Assert.notNull(deviceUnitCode, "deviceUnitCode 不能为空");
        Assert.notNull(switchState, "switchState 不能为空");
        List<String> deviceIdList = (List<String>)downParameter.get("device_id");

        List<Map<String, Object>> paramList = fillParams(deviceUnitCode, switchState);

        for (String deviceCode:
                deviceIdList) {
            for (Map<String, Object> downParameterMap:
                    paramList) {
                downParameterMap.put("device_id",deviceCode);
                log.info("classroom send:{}", downParameterMap);
                deviceServiceService.send(downParameterMap);
                try{
                    Thread.sleep(delayTime);
                }catch(Exception ex){
                    ex.printStackTrace();
                }
            }
        }
    }
}
